package plgutils

import (
	"bufio"
	"dgo/MyProj/PrjDBUtils"
	"dgo/MyProj/PrjHttpClt"
	"dgo/MyProj/PrjHttpUtils"
	"dgo/goutils/utils"
	"dgo/plg/plgbase"
	"dgo/plg/plgnet"
	"fmt"
	"gitee.com/ymofen/gobase/evthub"
	"gitee.com/ymofen/gobase/golog"
	"gitee.com/ymofen/gobase/gotask/grouptask"
	"gitee.com/ymofen/supervalue"
	"os"
	"strings"
	"sync/atomic"
	"time"
)

/*
兼容.db
*/
type DbPlglMakerMix struct {
	workflag int32
	PlgBase
	last_reload_t    time.Time
	templ_parse_ver  int
	checkremove_flag int
	msglst           *utils.SyncCycleList
	lstPlg           utils.GSyncMapGroup
	timer            *utils.Timer
	filenameJson     string
	filenameText     string
	datasource       string
	srctxtData       string
	srctxtRowSep     string
	srctxtValSep     string
	srcJSON          *wrapper.SuperValue
	srcPlg           *PlgBaseInnerPlug
	srcPlgArgs       string
	sql              string
	url              string
	conf_templ       string

	rowcmdid string
	rowcmd   *evthub.EvtNode

	jsonPreprocCmd *evthub.EvtNode

	startuptime time.Time

	firstdelay time.Duration

	reloadmsg string
}

type plg_info struct {
	id         string
	loadflag   int8
	confstr    string
	changedlst int8
	uptime     time.Time
}

func (this *DbPlglMakerMix) checkGetPlgInfo(id string, newflag bool) *plg_info {
	if newflag {
		rec := this.lstPlg.LoadOrStoreFunc(id, func() interface{} {
			rval := &plg_info{id: id}
			return rval
		}, nil).(*plg_info)
		return rec
	} else {
		rec := this.lstPlg.Get(id, (*plg_info)(nil)).(*plg_info)
		return rec
	}
}

func (this *DbPlglMakerMix) String() string {
	return fmt.Sprintf("DbPlglMakerMix-%s", this.PlugId)
}

func (this *DbPlglMakerMix) innerDoFromSrcPlg() {
	obj := this.srcPlg.CheckGetPlug()
	if obj == nil {
		return
	}

	json := wrapper.NewSVArray()
	if wrapper.TryFillJsonStatus(obj, json, this.srcPlgArgs) {
		this.innerDoFromJSON(json)
	} else {
		this.reloadmsg = fmt.Sprintf("[%s][%s]不支持IFillJsonStatus", utils.NowString(), this.srcPlg.StatusString())
	}
}

func (this *DbPlglMakerMix) innerDoFromDB(forcesave2local byte) {
	sql := ReplacePlaceholderForFileName(this.sql)
	dao := PrjDBUtils.NewDAOHelper(this.datasource)
	defer dao.Close()

	json := wrapper.NewSVArray()

	_, err := dao.QueryData(sql, json, nil)
	if err != nil {
		golog.Warnf("获取数据:%s异常, %s", sql, err.Error())
		return
	}
	cnt := this.innerDoFromJSON(json)
	if cnt > 0 && len(this.filenameJson) > 0 && (forcesave2local == 1 || !utils.FileIsExists(this.filenameJson)) {
		utils.ForceCreateFilePath(this.filenameJson)
		json.SaveFile2(this.filenameJson, true, false)
	}
}

func (this *DbPlglMakerMix) innerDoFromUrl(forcesave2local byte) {
	url := ReplacePlaceholderForFileName(this.url)
	json, err := PrjHttpClt.GetUrlAsJSON(url)
	if err != nil {
		this.LogWarnMessage("获取URL:%s异常, %s", url, err.Error())
		return
	}
	cnt := this.innerDoFromJSON(json)
	if cnt > 0 && len(this.filenameJson) > 0 && (forcesave2local == 1 || !utils.FileIsExists(this.filenameJson)) {
		utils.ForceCreateFilePath(this.filenameJson)
		json.SaveFile2(this.filenameJson, true, false)
	}
}

func (this *DbPlglMakerMix) innerDoFromTextFile(txtfile string) bool {
	if len(txtfile) == 0 {
		return false
	}

	var readf *os.File
	var err error

	readf, err = os.Open(txtfile)
	if err != nil {
		this.reloadmsg = fmt.Sprintf("读取文件%s, 异常:%s", txtfile, err.Error())
		return true
	}
	defer func() {
		if readf != nil {
			readf.Close()
		}
	}()
	reader := bufio.NewReader(readf)

	json := wrapper.NewSVArray()
	n := wrapper.TextReader2SVArray(reader, json)
	this.innerDoFromJSON(json)
	this.reloadmsg = fmt.Sprintf("%s,加载成功, 条数:%d", txtfile, n)
	return true
}

func (this *DbPlglMakerMix) innerDoFromJsonFile() {
	fn := ReplacePlaceholderForFileName(this.filenameJson)
	json, err := wrapper.NewSVFromFileCache(fn, true)
	if err != nil {
		golog.Warnf("获取数据:%s异常, %s", fn, err.Error())
		return
	}
	defer json.Clear()
	this.innerDoFromJSON(json)
}

func (this *DbPlglMakerMix) ReloadList(lst *wrapper.SuperValue) {
	if lst == nil {
		return
	}
	this.innerDoFromJSON(lst)
}

func (this *DbPlglMakerMix) innerDoFromJSON(json *wrapper.SuperValue) (n int) {

	cmdproc := this.jsonPreprocCmd
	if cmdproc != nil {
		ok := true
		cmdproc.Execute(0, json, &ok)
		if !ok { // 忽略
			return 0
		}
	}

	var lst *wrapper.SuperValue
	if json.IsArray() {
		lst = json
	} else {
		lst = json.ValueByName("list")
	}

	if lst == nil {
		return 0
	}

	conf_n := 0
	load_n := 0
	close_n := 0

	var innerCheckReload = func(plgTxt string) {
		plgTxt = plgbase.PlgReplacePlaceholder(plgTxt)
		itmconf, err := wrapper.NewSVFromBufCache([]byte(plgTxt), true)
		if err != nil {
			this.LogWarnMessage("模版解析异常:%s", plgTxt)
		} else {
			defer itmconf.Clear()
			id := itmconf.StringByName("id", "")
			plgtype := itmconf.StringByName("type", "")
			if len(id) > 0 && len(plgtype) > 0 { // 有效的插件配置
				plg := this.checkGetPlgInfo(id, true)
				if plg.confstr != plgTxt || (plgtype != "NONE" && plgbase.FindPluginByID(id) == nil) {
					plg.changedlst = itmconf.Int8ByPath("changedlst", 1)
					_, _, e1 := plgbase.PlgCheckReloadFromJSON(itmconf)
					if e1 != nil {
						this.LogWarnMessage("处理插件异常:%s\r\n%s", e1.Error(), plgTxt)
					}
					plg.confstr = plgTxt
					plg.uptime = time.Now()
					load_n++
				}
				plg.loadflag = 1
				conf_n++
			}
		}
	}

	//[{"id":"xxx"}]
	lst.Range(func(key string, rowval *wrapper.SuperValue) bool {
		rowcmd := this.rowcmd
		if rowcmd != nil {
			ok := true
			rowcmd.Execute(0, rowval, &ok)
			if !ok { // 忽略
				return true
			}
		}
		// 插件被进制
		if rowval.Int8ByName("__plug_disable", -1) == 1 {
			return true
		}
		plgTxt := this.conf_templ
		if len(plgTxt) > 0 { // 进行解析
			rowval.Range(func(key string, val *wrapper.SuperValue) bool {
				str := val.String()
				if this.templ_parse_ver >= 1 {
					plgTxt = strings.ReplaceAll(plgTxt, fmt.Sprintf("[%s]", key), str)
				} else {
					plgTxt = strings.ReplaceAll(plgTxt, fmt.Sprintf("$$%s$$", key), str)
					if len(str) > 0 {
						plgTxt = strings.ReplaceAll(plgTxt, fmt.Sprintf("\"$$[%s]$$\"", key), val.String())
					} else {
						plgTxt = strings.ReplaceAll(plgTxt, fmt.Sprintf("\"$$[%s]$$\"", key), "{}")
					}
				}

				return true
			})
		} else {
			plgTxt = rowval.String()
		}

		innerCheckReload(plgTxt)
		return true
	})

	if this.checkremove_flag == 1 {
		this.lstPlg.Range(func(key, value interface{}) bool {
			plg := value.(*plg_info)
			if plg.loadflag == 0 {
				this.lstPlg.Remove(key)
				plgbase.PlgLoadCloseConfEx(plg.id, plg.changedlst)
				close_n++
			} else {
				plg.loadflag = 0
			}
			return true
		})
	}

	if load_n > 0 || close_n > 0 {
		this.LogInfoMessage("配置有效插件:%d, 加载更新插件:%d, 关闭插件:%d", conf_n, load_n, close_n)
	}

	return conf_n
}

func (this *DbPlglMakerMix) innerDo() {
	if !this.last_reload_t.IsZero() && time.Since(this.last_reload_t) < this.timer.GetInterval() {
		return
	}

	if !atomic.CompareAndSwapInt32(&this.workflag, 0, 1) {
		return
	}

	logdetail := time.Since(this.startuptime).Seconds() < 10
	if logdetail {
		this.LogInfoMessage("开始加载数据")
	}

	defer func() {
		this.workflag = 0
		this.last_reload_t = time.Now()
		if logdetail {
			this.LogInfoMessage("加载完成")
		}
	}()

	if this.srcPlg.IsValid() {
		this.innerDoFromSrcPlg()
	} else if this.srcJSON != nil {
		this.innerDoFromJSON(this.srcJSON)
	} else if len(this.srctxtData) > 0 {
		json := wrapper.NewSVArray()
		wrapper.TextData2SVArray(this.srctxtData, json, "\n", ",", true)
		this.innerDoFromJSON(json)
	} else if this.innerDoFromTextFile(this.filenameText) {
		// ok;
	} else if len(this.filenameJson) > 0 {
		if utils.FileIsExists(this.filenameJson) {
			this.innerDoFromJsonFile()
		} else {
			this.LogWarnMessage("文件不存在:%s", this.filenameJson)
		}
	} else if len(this.sql) > 0 {
		this.innerDoFromDB(0)
	} else if len(this.url) > 0 {
		this.innerDoFromUrl(0)
	} else {
		this.reloadmsg = fmt.Sprintf("[%s]无法获取配置信息，请检查配置")
	}

}

func (this *DbPlglMakerMix) closeRowCmd() {
	if len(this.rowcmdid) > 0 {
		this.rowcmd = nil
		evthub.DefaultEvtHub.ReleasesEvtNode(this.rowcmdid)
		this.rowcmdid = ""
	}
}

func (this *DbPlglMakerMix) closePreprocCmd() {
	if this.jsonPreprocCmd != nil {
		evthub.DefaultEvtHub.ReleasesEvtNode(this.jsonPreprocCmd.GetId())
		this.jsonPreprocCmd = nil
	}
}

/*
*

			  {
			    "id": "plg-maker",
			    "type": "utils.plug.maker.mix",
			    "conf": {


			      "srcPlg":"",
			      "srcPlgArgs":"",

			      "filename-json":"",
	              "filename-text":"",

			      "src-txtdata":"id\nBJF1\n",
		          "src-json":[{}],



			      "url":"",

				  "datasource":"main",
			      "sql":"select * from ",

			      "interval":30,

			      "checkremove-flag":0,
			      "templ-parse-ver":1,    // >= 1 $$key$$ 先进行解析, [field] 进行字段替换
			      "conf_templ":  {
			         "id": "$$id$$-A",
			         "type": "gnss.rtcm.analyzer",
			         "conf": {
			           "input": {
			             "id": "kpl-dc-caster",
			             "topic": "$$id$$"
			           },
			           "dc": "kpl-dc-caster",
			           "dc-pid": "$$id$$",
			           "spp-url": "http://119.96.169.117:3000/plug/spp/do?mp=$mp$&timestamp=0",
			           "spp-min-interval-sec": 10,
			           "skyplot-url": "http://119.96.169.117:3000/plug/skyplot/do?all=1&x=$x$&y=$y$&z=$z$&satids=$satids$&timestamp=$timpstamp$&resp=json",
			           "skyplot-min-interval-sec": 10,
			           "snr-interval-sec": 10,
			           "status_o": {
			             "id": "core-wsclt",
			             "topic": "/kpl-gnss/ntripsvr/status"
			           }
			         }
			       }
			    }
			  }

filename-json: 从文件中读取JSON

"datasource":"main",
"sql":"select * from ",  // 从数据表中读取

checkremove-flag: 新的数据中如果不存在,则进行移除改插件

	"templ-parse-ver":1,    // >= 1 $$key$$ 先进行解析, [field] 进行字段替换
*/
func (this *DbPlglMakerMix) ReloadConf(conf *wrapper.SuperValue) error {
	if conf == nil {
		return nil
	}

	if this.startuptime.IsZero() {
		this.startuptime = time.Now()
	}

	if this.timer == nil {
		this.timer = utils.NewTimer()
		this.timer.OnTimer = func(tag interface{}) {
			grouptask.DefaultGroupTask().PostTaskFunc(this, this.innerDo)
		}
		this.timer.ConfigInterval(60*time.Second, 0)
	}

	if this.msglst == nil {
		this.msglst = utils.NewSyncCycleList()
	}

	{
		str := conf.StringByName("row-proc", "")
		if str != this.rowcmdid {
			this.closeRowCmd()
			if len(str) > 0 {
				this.rowcmd = evthub.DefaultEvtHub.CheckGetEvtNode(str, true)
			}
			this.rowcmdid = str
		}
	}

	{
		str := conf.StringByName("json-preproc", "")
		if this.jsonPreprocCmd != nil && this.jsonPreprocCmd.GetId() != str {
			this.closePreprocCmd()
		}
		if len(str) > 0 {
			this.jsonPreprocCmd = evthub.DefaultEvtHub.CheckGetEvtNode(str, true)
		}
	}

	this.templ_parse_ver = conf.IntByName("templ-parse-ver", 0)

	this.checkremove_flag = conf.IntByName("checkremove-flag", 1)

	conf.CheckExistsIntFunc("interval", func(val int64) {
		this.timer.ConfigInterval(time.Second*time.Duration(val), 0)
	})

	conf.CheckExistsIntFunc("reload-interval-secs", func(val int64) {
		this.timer.ConfigInterval(time.Second*time.Duration(val), 0)
	})

	conf.CheckExistsStrFunc("conf_templ", func(strv string) {
		if this.templ_parse_ver >= 1 {
			strv = utils.ReplacePlaceholder(strv, "$$", "$$")
		}
		if this.conf_templ != strv {
			this.conf_templ = strv
		}
	})

	isChanged := false

	//strv := conf.StringByName("filename-json", "")
	//if this.filename_json != strv {
	//	this.filename_json = strv
	//	isChanged = true
	//}

	if this.srcPlg == nil {
		this.srcPlg = PlgNewInnerPlugEx(this)
	}
	this.srcPlg.ReloadConf(conf.ValueByName("srcPlg"))
	this.srcPlgArgs = utils.ReplacePlaceholder(conf.StringByName("srcPlgArgs", ""), "$$", "$$")

	lst := conf.ValueByName("src-json")
	if lst != nil {
		tmp := lst.Clone()
		if this.srcJSON == nil {
			this.srcJSON = tmp
			isChanged = true
		} else {
			if tmp.String() != this.srcJSON.String() {
				this.srcJSON = tmp
				isChanged = true
			}
		}
	}

	conf.CheckStrFunc("filename-json", func(strv string) {
		strv = utils.ReplacePlaceholder(strv, "$$", "$$")
		if this.filenameJson != strv {
			this.filenameJson = strv
			isChanged = true
		}
	})

	conf.CheckStrFunc("filename-text", func(strv string) {
		strv = utils.ReplacePlaceholder(strv, "$$", "$$")
		if this.filenameText != strv {
			this.filenameText = strv
			isChanged = true
		}
	})

	conf.CheckExistsStrFunc("src-txtdata", func(strv string) {
		if this.srctxtData != strv {
			this.srctxtData = strv
			isChanged = true
		}
	})

	conf.CheckStrFunc("sql", func(strv string) {
		this.datasource = conf.StringByName("datasource", "main")
		strv = utils.ReplacePlaceholder(strv, "$$", "$$")
		if this.sql != strv {
			this.sql = strv
			isChanged = true
		}
	})

	conf.CheckStrFunc("url", func(strv string) {
		strv = utils.ReplacePlaceholder(strv, "$$", "$$")
		if this.url != strv {
			this.url = strv
			isChanged = true
		}
	})

	plgbase.AddSysReloadNotify(this, func() {
		utils.DefaultWorkers().PostTaskFunc(this, this.innerDo)
	})

	if isChanged {
		loaddelay := time.Duration(conf.Int64ByName("load-delay-secs", 20)) * time.Second
		if loaddelay <= 0 {
			this.innerDo()
		} else {
			time.AfterFunc(loaddelay, func() {
				utils.DefaultWorkers().PostTaskFunc(this, this.innerDo)
			})
		}
	}

	return nil
}

func (this *DbPlglMakerMix) LogInfoMessage(s string, args ...interface{}) {
	this.msglst.LogMsg(s, args...)
	golog.DefaultLogger().LogMsgfWithSkip(golog.LevelInfo, 2, s, args...)
}

func (this *DbPlglMakerMix) LogWarnMessage(s string, args ...interface{}) {
	this.msglst.LogMsg(s, args...)
	golog.DefaultLogger().LogMsgfWithSkip(golog.LevelWarn, 2, s, args...)
}

func (this *DbPlglMakerMix) OnHttpStatus(rec *plgnet.PlgHttpRec) (rval interface{}, errcode int, err error) {
	itype := rec.QryAsInt("type", 0)
	if itype == 99 {
		json := wrapper.NewSVObject()
		json.SetKeyValue("templ-parse-ver", this.templ_parse_ver)
		if this.srcPlg.IsValid() {
			json.SetKeyValue("srcPlg", this.srcPlg.StatusString())
			json.SetKeyValue("srcPlgArgs", this.srcPlgArgs)
		}

		if len(this.datasource) > 0 {
			json.SetKeyValues("sql", fmt.Sprintf("[%s]:%s", this.datasource, this.sql))
		}
		json.SetKeyValues("url", this.url)
		json.SetKeyValues("file-json", this.filenameJson)
		json.SetKeyValues("file-text", this.filenameText)
		json.SetKeyValue("reloadmsg", this.reloadmsg)
		json.SetKeyValues("now", utils.NowString())

		if rec.QryAsInt("json", 0) == 1 {
			PrjHttpUtils.ResponseAsJSON(rec.RespW, json.AsJSONStringEx(false, true))
		} else {
			PrjHttpUtils.JSON2TableRec(rec.RespW, "", json.AsJSONString(false))
		}
	} else if itype == 98 {
		rec.ResponseSyncListNEx(this.msglst)
	} else if itype == 96 {
		this.innerDo()
		this.LogInfoMessage("重置配置, from OnHttpStatus")
		rec.ResponseJSONValues("code", 0)
	} else if itype == 95 {
		if len(this.filenameJson) == 0 {
			rec.ResponseJSONValues("code", -1, "msg", "未设置本地配置文件, 不能进行本地存储")
			return
		} else {
			err0 := utils.ForceCreateFilePath(this.filenameJson)
			if err0 != nil {
				rec.ResponseJSONValues("code", -1, "msg", err0.Error())
				return
			}
			if len(this.sql) > 0 {
				this.innerDoFromDB(1)
			} else if len(this.url) > 0 {
				this.innerDoFromUrl(1)
			} else {
				rec.ResponseJSONValues("code", -1, "msg", "远程加载配置未设定")
				return
			}
		}
		this.LogInfoMessage("下载配置到本地, from OnHttpStatus")
		rec.ResponseJSONValues("code", 0)
	} else if itype == 1 {
		searchval := rec.QryAsString("searchval", "")
		json := wrapper.NewSVArrayCache(true)
		defer json.Clear()
		sn := 0
		this.lstPlg.ListRangeV2(func(key, value interface{}) bool {
			pojo := value.(*plg_info)
			ok := true
			if len(searchval) > 0 {
				return strings.Contains(pojo.id, searchval)
			}
			return ok
		}, func(k0, v0, k1, v1 interface{}) bool {
			p0 := v0.(*plg_info)
			p1 := v1.(*plg_info)

			if p0.uptime.Unix() != p1.uptime.Unix() {
				return p0.uptime.After(p1.uptime)
			}
			return p0.id < p1.id
		}, func(key, val interface{}) bool {
			pojo := val.(*plg_info)
			itm := json.AppendObject()
			itm.SetKeyValue("sn", sn)
			itm.SetKeyValue("id", pojo.id)
			itm.SetKeyValue("uptime", utils.DateTimeString2(pojo.uptime))
			itm.SetKeyValue("opera", fmt.Sprintf("【%s】【%s】",
				fmt.Sprintf("<a href='status?type=2&id=%s' target='_blank'>detail</a>", pojo.id),
				fmt.Sprintf("<a href='status?type=3&id=%s' target='_blank'>reload</a>", pojo.id),
			))
			sn++
			return true
		})

		if rec.QryAsInt("json", 0) == 1 {
			PrjHttpUtils.ResponseAsJSON(rec.RespW, json.AsJSONStringEx(false, false))
		} else {
			PrjHttpUtils.JSON2Table(rec.RespW, "", json.AsJSONString(false))
		}
	} else if itype == 2 {
		id := rec.QryAsString("id", "")
		if len(id) == 0 {
			rec.ResponseText("param id is empty!!!")
		} else {
			var sb utils.BytesBuilder
			plginfo := this.checkGetPlgInfo(id, false)
			if plginfo == nil {
				rec.ResponseText(fmt.Sprintf("plg %d info is not found!"))
				return
			}
			plgObj := plgbase.FindPluginByID(plginfo.id)
			sb.Appendf("id:%s\n", plginfo.id)
			sb.Appendf("conf:%s\n", plginfo.confstr)
			sb.Appendf("uptime:%s\n", utils.DateTimeString3(plginfo.uptime))
			sb.Appendf("plgstatus:(%p):%+v\n", plgObj, plgObj)
			rec.ResponseText(sb.String())
		}
	} else if itype == 3 {
		id := rec.QryAsString("id", "")
		if len(id) == 0 {
			rec.ResponseText("param id is empty!!!")
		} else {
			plginfo := this.checkGetPlgInfo(id, false)
			if plginfo == nil {
				rec.ResponseText(fmt.Sprintf("plg %d info is not found!", id))
				return
			}
			json, err0 := wrapper.NewSVFromBufCache([]byte(plginfo.confstr), true)
			if err0 != nil {
				rec.ResponseText(fmt.Sprintf("plg %s conf json parse err:%s, conf:%s", id, err0.Error(), plginfo.confstr))
				return
			}
			defer json.Clear()
			_, _, err0 = plgbase.ReloadPlgFromJSON(json)
			if err0 != nil {
				rec.ResponseText(fmt.Sprintf("plg %s conf load err:%s, conf:%s", id, err0.Error(), plginfo.confstr))
				return
			}

			var sb utils.BytesBuilder
			plgObj := plgbase.FindPluginByID(plginfo.id)
			sb.Appendf("id:%s\n", plginfo.id)
			sb.Appendf("conf:%s\n", plginfo.confstr)
			sb.Appendf("uptime:%s\n", utils.DateTimeString3(plginfo.uptime))
			sb.Appendf("plgstatus:(%p):%+v\n", plgObj, plgObj)
			rec.ResponseText(sb.String())
		}
	} else {
		var sb utils.BytesBuilder
		PrjHttpUtils.AppendIndexBody(&sb, "status", "status?type=99")
		PrjHttpUtils.AppendIndexBody(&sb, "msglist", "status?type=98&n=100&searchval=")
		PrjHttpUtils.AppendIndexBody(&sb, "reload", "status?type=96")
		PrjHttpUtils.AppendIndexBody(&sb, "save2local", "status?type=95")
		PrjHttpUtils.AppendIndexBody(&sb, "lst", "status?type=1&searchval=")
		PrjHttpUtils.AppendIndexBody(&sb, "detail", "status?type=2&id=")
		PrjHttpUtils.AppendIndexBody(&sb, "forcereload-item", "status?type=3&id=")
		PrjHttpUtils.ResponseBodyHtml(rec.RespW, sb.String())
	}
	return
}

func (this *DbPlglMakerMix) checkTemplateFromJson(val *wrapper.SuperValue) *wrapper.SuperValue {
	if val == nil || val.Count() == 0 {
		return nil
	}
	plgTxt := this.conf_templ
	val.Range(func(key string, val *wrapper.SuperValue) bool {
		plgTxt = strings.ReplaceAll(plgTxt, fmt.Sprintf("$$%s$$", key), val.String())
		return true
	})

	json, err := wrapper.NewSVFromBuf([]byte(plgTxt))
	if err != nil {
		golog.Warnf("模版解析异常:%s", plgTxt)
	} else {
		_, _, e1 := PlgOnPlugRecvCmd(json)
		if e1 != nil {
			golog.Warnf("处理插件异常:%s\r\n%s", e1.Error(), plgTxt)
		}
	}
	return json
}

func (this *DbPlglMakerMix) OnObjectNotify(sender interface{}, notifytype int, data interface{}) (rval interface{}, err error) {
	if notifytype == utils.NOTIFY_TYPE_SETCONF {
		if conf, ok := data.(*wrapper.SuperValue); ok {
			err = this.ReloadConf(conf)
		} else {
			err = fmt.Errorf("非法的JSON配置")
		}
	} else if notifytype == utils.NOTIFY_TYPE_RELEASE {
		this.ReleaseFlag = 1
		this.timer.Close()
		this.closeRowCmd()
		this.closePreprocCmd()
		plgbase.DelSysReloadNotify(this)
	}
	return
}

func CreateDbPlglMakerMixFunc(args ...interface{}) (rval interface{}, err error) {
	obj := &DbPlglMakerMix{}
	if len(args) > 0 {
		if str, ok := args[0].(string); ok {
			obj.PlugId = str
		}
	}

	rval = obj
	return
}
